/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2005
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
* 
* Author's email :    insane@dees.ufmg.br
* Author's website :  http://www.dees.ufmg.br/insane
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package br.ufmg.dees.insane.prep;

import java.util.List;

import br.ufmg.dees.insane.model.geo.GCurve;
import br.ufmg.dees.insane.model.geo.GPoint;
import br.ufmg.dees.insane.model.geo.GRegion;

public class TrilinearToSeren extends Trilinear{
	
//*****************************************************************************
	
	public TrilinearToSeren(int ln, int le, int nppe, GRegion rg){
		this.lastNode = ln;
		this.lastElement = le;
		this.nPointsPerElement = nppe;
		this.region = rg;
		
		this.mapNodes();
		this.conectivite();
	}
	
//*****************************************************************************
	
	private void mapNodes(){
		int nPointsElementSide = nPointsPerElement/3 + 1;
		
		List curves = this.region.getCurves();
		GPoint[] curve1 = ((GCurve)curves.get(0)).getDiscrete((GPoint)region.getFirstPoint());
		GPoint[] curve2 = ((GCurve)curves.get(1)).getDiscrete(curve1[curve1.length-1]);
		GPoint[] curve3 = ((GCurve)curves.get(2)).getDiscrete(curve2[curve2.length-1]);
		
		int nPoints1 = curve1.length;
		
		double x, y;
		int i, ci, cj, ck;
		for (int j = 0; j < nPoints1; j++) {
			cj = nPoints1-(j+1);
			double v = (double)j/(nPoints1-1);
			for (int k = (nPoints1-j-1); k >= 0; k--) {
				i = nPoints1-j-k-1;
				if ( j%(nPointsElementSide-1)==0 || k%(nPointsElementSide-1)==0 || i%(nPointsElementSide-1)==0 ) {
					lastNode++;
					double u = (double)i/(nPoints1-1);
					double w = (double)k/(nPoints1-1);
					ci = nPoints1-(i+1);
					cj = nPoints1-(j+1);
					ck = nPoints1-(k+1);
					x = (u/(1.0-v)*curve2[ j].getX()+w/(1.0-v)*curve3[cj].getX()
						+w/(1.0-u)*curve1[ i].getX()+v/(1.0-u)*curve2[ci].getX()
						+v/(1.0-w)*curve3[ k].getX()+u/(1.0-w)*curve1[ck].getX()
						-w*curve1[0].getX()-u*curve2[0].getX()-v*curve3[0].getX() ) / 2.0;
					y = (u/(1.0-v)*curve2[ j].getY()+w/(1.0-v)*curve3[cj].getY()
						+w/(1.0-u)*curve1[ i].getY()+v/(1.0-u)*curve2[ci].getY()
						+v/(1.0-w)*curve3[ k].getY()+u/(1.0-w)*curve1[ck].getY()
						-w*curve1[0].getY()-u*curve2[0].getY()-v*curve3[0].getY() ) / 2.0;
					if ( j == (nPoints1-1) ) {
						x = curve2[nPoints1-1].getX();
						y = curve2[nPoints1-1].getY();
					}
					if ( i == (nPoints1-1) ) {
						x = curve1[nPoints1-1].getX();
						y = curve1[nPoints1-1].getY();
					}
					if ( k == (nPoints1-1) ) {
						x = curve3[nPoints1-1].getX();
						y = curve3[nPoints1-1].getY();
					}
					MapNode mn = new MapNode(x, y, lastNode);
					if ( j==0 || k==0 || i==0 ) {
						mn.setBoundary( true );
					}
					this.nodes.add(mn);
				}
			}
		}
	}
	
//*****************************************************************************
	
	private void conectivite(){
		List curves = this.region.getCurves();
		GPoint[] curve1 = ((GCurve)curves.get(0)).getDiscrete((GPoint)region.getFirstPoint());
		int nPoints1 = curve1.length;
		int nPointsElementSide = nPointsPerElement/3 + 1;
		
		MapNode[] conec = new MapNode[nPointsPerElement];
		int nElements1 = (nPoints1 - 1)/(nPointsElementSide - 1);
		int nElements = nElements1;
		int element = this.lastElement;
		int pht = 0;
		int pha = 0;
		int pit = 0;
		int pia = 0;
		//	algoritimo para gerar elemento no sentido anti-horario
		for (int i = 0; i < nElements1; i++) {
			pha = nElements*(nPointsElementSide-1) + 1;
			pia = (nPointsElementSide-2)*(nElements*2);
			// triangulos na vertical "/\"
			for (int j = 0; j < nElements; j++) {
				element++;
				int no = -1;
				// lado direito "\"
				for (int k = (nPointsElementSide-1); k >= 0; k--) {
					no++;
					conec[no] = (MapNode)nodes.get( pht+pit+j*(nPointsElementSide-1)+k+1 -1 );
				}
				// lado esquerdo "/"
				for (int k = 0; k < (nPointsElementSide-2); k++) {
					no++;
					conec[no] = (MapNode)nodes.get( pht+pit+pha+j*2+k*(2*nElements)+1 -1 );
				}
				// vertice inferior esquerdo ".  "
				no++;
				conec[no] = (MapNode)nodes.get( pht+pit+pha+pia+j*(nPointsElementSide-1)+1 -1 );
				// lado inferior "__"
				for (int k = (nPointsElementSide-3); k >= 0; k--) {
					no++;
					conec[no] = (MapNode)nodes.get( pht+pit+pha+j*2+k*(2*nElements)+2 -1 );
				}
				MapElement me = new MapElement(element, conec, conec);
				me.setType('T','S');
				this.elements.add(me);
			}
			// triangulos invertidos "\/"
			for (int j = 0; j < (nElements-1); j++) {
				element++;
				int no = -1;
				// lado esquerdo "\"
				for (int k = 1; k <= nPointsElementSide; k++) {
					no++;
					conec[no] = (MapNode)nodes.get( pht+pit+pha+pia+j*(nPointsElementSide-1)+k -1 );
				}
				// lado direito "/"
				for (int k = (nPointsElementSide-3); k >= 0; k--) {
					no++;
					conec[no] = (MapNode)nodes.get( pht+pit+pha+(j+1)*2+k*(2*nElements)+1 -1 );
				}
				// vertice superior direito "  *"
				no++;
				conec[no] = (MapNode)nodes.get( pht+pit+(j+1)*(nPointsElementSide-1)+1 -1 );
				// lado superior "--"
				for (int k = 0; k <= (nPointsElementSide-3); k++) {
					no++;
					conec[no] = (MapNode)nodes.get( pht+pit+pha+j*2+k*(2*nElements)+2 -1 );
				}
				MapElement me = new MapElement(element, conec, conec);
				me.setType('T','S');
				this.elements.add(me);
			}
			nElements--;
			pht = pht + pha;
			pit = pit + pia;
		}
		
	}
	
//*****************************************************************************
}

